/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of UHM (Unassembled HyperMatrix) sparse direct solver.
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#ifndef UHM_MATRIX_UHM_MATRIX_HXX
#define UHM_MATRIX_UHM_MATRIX_HXX

namespace uhm {

  typedef class Matrix_*    Matrix;

  extern void   set_hier_blocksize(int size);
  extern int    get_hier_blocksize();

  extern double matrix_buffer_used();
  extern double matrix_max_buffer_used();
  extern double matrix_flop();
  extern void   matrix_reset_flop();
  extern void   matrix_reset_buffer();

  extern void   merge(int datatype,
                      double *buf_s, int offm_s, int offn_s, int cs_s,
                      double *buf_t, int offm_t, int offn_t, int cs_t, 
                      int is_erase);

  extern void   merge(int datatype,
                      double *buf_s, int offm_s, int offn_s, int cs_s,
                      double *buf_t, int offm_t, int offn_t, int cs_t,
                      int m, int n,
                      int is_erase);

  extern void   copy(int datatype,
                     double *buf_s, int offm_s, int offn_s, int cs_s,
                     double *buf_t, int offm_t, int offn_t, int cs_t,
                     int is_erase);


  extern void   copy(int datatype,
                     double *buf_s, int offm_s, int offn_s, int cs_s, 
                     double *buf_t, int offm_t, int offn_t, int cs_t,
                     int m, int n,
                     int is_erase);

  
  // --------------------------------------------------------------
  // ** Abstract class for the interface 

  // connected to element object
  class Matrix_ {
  public:
    Matrix_() { }
    Matrix_( int datatype, int fs, int ss, int n_rhs, int symmetry ) { }
    virtual ~Matrix_() { }
    virtual bool disp()=0;
    virtual bool disp( FILE *stream )=0;

    virtual bool write_to_ooc(FILE* stream, int mat)=0;
    virtual bool read_from_ooc(FILE* stream, int mat)=0;

    virtual bool export_matrix( FILE *stream, int mat )=0;
    virtual bool export_matrix( int &m, int &n,
			        std::vector< double > &val,
			        int mat)=0;
    virtual bool import_matrix( int m, int n, int lda,
			        std::vector< double > &val,
			        int mat)=0;

    virtual int  is_symmetry()=0;

    virtual int  is_created( int mat )=0;
    virtual int  is_buffer ( int mat )=0;
    virtual int  is_complex_datatype()=0;
    
    virtual int  get_datatype()=0;

    virtual std::pair<int,int> get_dimension()=0;

    virtual int  get_n_rhs()=0;
    virtual int  get_compressed_mat_dim()=0;

    virtual void create_without_buffer()=0;
    virtual void free()=0;

    virtual void copy_in ( int mat, void *buffer )=0;
    virtual void copy_out( int mat, void *buffer )=0;

    virtual void copy_in ( int mat, linal::Flat_ A )=0;
    virtual void copy_out( int mat, linal::Flat_ B )=0;

    virtual void create_buffer()=0;
    virtual void free_buffer()=0;

    virtual void create_buffer ( int mat )=0;
    virtual void free_buffer   ( int mat )=0;
    virtual std::pair<double*,int> get_buffer ( int mat )=0;

    virtual void merge( Matrix src, 
			int mat_s, int offm_s, int offn_s,
			int mat_t, int offm_t, int offn_t,
			int m, int n, int is_erase )=0;
    
    virtual void copy ( Matrix src, 
			int mat_s, int offm_s, int offn_s,
			int mat_t, int offm_t, int offn_t,
			int m, int n, int is_erase )=0;

    virtual void   random()=0;
    virtual void   random_spd( int uplo )=0;
    virtual void   triangularize( int uplo )=0;
    virtual void   set_rhs( int is_leaf )=0;
    virtual double get_residual()=0;
    virtual double get_lower_triangular_norm()=0;
    virtual void   check_solution()=0;
    virtual void   improve_solution()=0;

    // for checkin routine internally need
    virtual void backup( int mat )=0;
    virtual void restore( int mat, int is_merge )=0;
    virtual void apply_pivots( int mat )=0;
    virtual void set_zero( int mat )=0;
    // --------------------------------------------------------------
    virtual void chol()=0;
    virtual void solve_chol_1_x()=0;
    virtual void solve_chol_2_x()=0;
    virtual void check_chol_1()=0;
    virtual void check_chol_2()=0;
    virtual void solve_chol_1_r()=0;
    virtual void solve_chol_2_r()=0;
    // --------------------------------------------------------------
    virtual void chol_incpiv()=0;
    virtual void chol_piv()=0;
    virtual void solve_chol_piv_1_x()=0;
    virtual void solve_chol_piv_2_x()=0;
    virtual void check_chol_piv_1()=0;
    virtual void check_chol_piv_2()=0;
    virtual void solve_chol_piv_1_r()=0;
    virtual void solve_chol_piv_2_r()=0;
    // --------------------------------------------------------------
    virtual void ldl_nopiv()=0;
    virtual void solve_ldl_nopiv_1_x()=0;
    virtual void solve_ldl_nopiv_2_x()=0;
    virtual void check_ldl_nopiv_1()=0;
    virtual void check_ldl_nopiv_2()=0;
    virtual void solve_ldl_nopiv_1_r()=0;
    virtual void solve_ldl_nopiv_2_r()=0;
    // --------------------------------------------------------------
    virtual void ldl_incpiv()=0;
    virtual void ldl_piv()=0;
    virtual void solve_ldl_piv_1_x()=0;
    virtual void solve_ldl_piv_2_x()=0;
    virtual void check_ldl_piv_1()=0;
    virtual void check_ldl_piv_2()=0;
    virtual void solve_ldl_piv_1_r()=0;
    virtual void solve_ldl_piv_2_r()=0;

    // --------------------------------------------------------------
    virtual void lu_nopiv()=0;
    virtual void solve_lu_nopiv_1_x()=0;
    virtual void solve_lu_nopiv_2_x()=0;
    virtual void check_lu_nopiv_1()=0;
    virtual void check_lu_nopiv_2()=0;
    virtual void solve_lu_nopiv_1_r()=0;
    virtual void solve_lu_nopiv_2_r()=0;
    // --------------------------------------------------------------
    virtual void lu_incpiv()=0;
    virtual void lu_piv()=0;
    virtual void solve_lu_piv_1_x()=0;
    virtual void solve_lu_piv_2_x()=0;
    virtual void check_lu_piv_1()=0;
    virtual void check_lu_piv_2()=0;
    virtual void solve_lu_piv_1_r()=0;
    virtual void solve_lu_piv_2_r()=0;
    // --------------------------------------------------------------
    virtual void qr()=0;
    virtual void solve_qr_1_x()=0;
    virtual void solve_qr_2_x()=0;
    virtual void check_qr_1()=0;
    virtual void check_qr_2()=0;
    virtual void solve_qr_1_r()=0;
    virtual void solve_qr_2_r()=0;
    // --------------------------------------------------------------
  };
}

#endif
